home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1994 September / macformat-004.iso / Shareware City / Graphics / VideoToolbox ƒ / VideoToolboxSources / StringBounds.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-07-07  |  4.2 KB  |  139 lines  |  [TEXT/KAHL]

  1. /*
  2. StringBounds.c
  3.  
  4.     void StrBounds(char *str,Rect *bounds,long *count);
  5.     void StringBounds(const unsigned char *string,Rect *bounds,long *count);
  6. StrBounds accepts a C string. StringBounds accepts a pascal string.
  7. Both routines count--and compute the minimum bounding rectangle for--all the pixels that
  8. would be set black by calling DrawString with the given string with the
  9. current port's font, size, and style. Coordinates in the *bounds rect are
  10. relative to the current pen position. If no pixels would be set then *bounds is
  11. set to the empty rect (0,0,0,0). The current port is left untouched.
  12.  
  13. The measurements are based on a full rendering of the string in a private
  14. GWorld, without any clipping.
  15.  
  16. The bounds and count arguments are optional; they may be replaced by NULL.
  17.  
  18.     void CharBounds(char a,Rect *bounds,long *count);
  19. Creates a one-char string and calls StringBounds().
  20.  
  21. NOTES
  22.  
  23. bounds->right need not exactly equal the value returned by StringWidth(s),
  24. because StringWidth returns the displacement of the pen position, and some (e.g.
  25. italic) characters extend beyond that, while others (e.g. comma) extend less
  26. far. Similarly, bounds->left need not always be zero.
  27.  
  28. By QuickDraw's convention, each pixel is considered to lie below and to the
  29. right of the point that is used to address it. The bounding rectangle for a
  30. pixel at x,y, is SetRect(&r,x,y,x+1,y+1).
  31.  
  32. The code assumes ForeColor is black and that TextMode is srcOr, which are the 
  33. default settings for the GWorld that we create.
  34.  
  35. HISTORY:
  36. 1/17/94 dgp wrote it, based on discussion with Bart Farell and Manoj Gunwani.
  37. 2/22/94    dgp    added count argument, and made both bounds and count optional.
  38. 2/27/94    dgp since this routine is typically called repeatedly I save time
  39.             (0.2 s per call) by only allocating the GWorld once, and never
  40.             freeing it. It is reused on subsequent calls, resized appropriately
  41.             if necessary.
  42. */
  43. #include <VideoToolbox.h>
  44. #include <assert.h>
  45. #define SHOW_BITMAPS 0    // for debugging
  46.  
  47. void CharBounds(char a,Rect *bounds,long *countPtr)
  48. {
  49.     unsigned char string[]="\pA";
  50.     
  51.     string[1]=a;
  52.     StringBounds(string,bounds,countPtr);
  53. }
  54.  
  55. void StrBounds(char *s,Rect *boundsPtr,long *countPtr)
  56. {
  57.     StringBounds(c2pstr(s),boundsPtr,countPtr);
  58.     p2cstr((unsigned char *)s);
  59. }
  60.  
  61. void StringBounds(const unsigned char *s,Rect *boundsPtr,long *countPtr)
  62. {
  63.     static GWorldPtr our=NULL;
  64.     GWorldPtr old;
  65.     GDHandle oldDevice;
  66.     FontInfo f;
  67.     Rect r;
  68.     register unsigned long *pix,blank;
  69.     register int x,y;
  70.     register long count=0;
  71.     int n;
  72.     OSErr error;
  73.     Rect bounds;
  74.     char string[40];
  75.  
  76.     assert(StackSpace()>4000);
  77.     GetFontInfo(&f);
  78.     SetRect(&r,0,-f.ascent,StringWidth(s),f.descent);    // nominal size
  79.     InsetRect(&r,-(f.widMax+2),-(f.leading+2));         // add margin
  80.  
  81.     // draw string into a new GWorld
  82.     if(our!=NULL){
  83.         DisposeGWorld(our);
  84.         our=NULL;
  85.     }
  86.     if(our==NULL){
  87.         error=NewGWorld(&our,1,&r,NULL,NULL,keepLocal|useTempMem);
  88.         if(error)error=NewGWorld(&our,1,&r,NULL,NULL,keepLocal);
  89.     }else
  90.         error=UpdateGWorld(&our,1,&r,NULL,NULL,clipPix);
  91.     if(error)PrintfExit("StringBounds: NewGWorld/UpdateGWorld error %d.\n",error);
  92.     GetGWorld(&old,&oldDevice);
  93.     SetGWorld(our,NULL);
  94.     TextFace(old->txFace);
  95.     TextFont(old->txFont);
  96.     TextSize(old->txSize);
  97.     EraseRect(&our->portRect);
  98.     MoveTo(0,0);
  99.     DrawString(s);
  100.     SetGWorld(old,oldDevice);
  101.     if(SHOW_BITMAPS){
  102.         PrintfGWorld(our);
  103.         gets(string);
  104.     }
  105.  
  106.     // measure the bounding box, and count the black pixels
  107.     r=our->portRect;
  108.     SetRect(&bounds,r.right,r.bottom,r.left,r.top);
  109.     n=r.right-r.left;
  110.     pix=(unsigned long *)malloc(n*sizeof(*pix));
  111.     if(pix==NULL)PrintfExit("StringBounds: Couldn't allocate %ld bytes.\n"
  112.         ,n*sizeof(long));
  113.     SetGWorld(our,NULL);
  114.     OffsetRect(&bounds,-r.left,-r.top);
  115.     for(y=0;y<r.bottom-r.top;y++){
  116.         GetPixelsQuickly(r.left,r.top+y,pix,n);
  117. //        if(y==0)blank=pix[0];
  118.         for(x=n-1;x>=0;x--)if(pix[x]!=0){
  119.             count++;
  120.             if(x<bounds.left)bounds.left=x;
  121.             if(x>=bounds.right)bounds.right=x+1;
  122.             if(y<bounds.top)bounds.top=y;
  123.             if(y>=bounds.bottom)bounds.bottom=y+1;
  124.         }
  125.     }
  126.     OffsetRect(&bounds,r.left,r.top);
  127.     if(SHOW_BITMAPS){
  128.         InvertRect(&bounds);
  129.         PrintfGWorld(our);
  130.         gets(string);
  131.     }
  132.     SetGWorld(old,oldDevice);
  133.     if(EmptyRect(&bounds))SetRect(&bounds,0,0,0,0);
  134.     free(pix);    
  135. //    DisposeGWorld(our);
  136.     if(boundsPtr!=NULL)*boundsPtr=bounds;
  137.     if(countPtr!=NULL)*countPtr=count;
  138. }
  139.